package org.aseclipse.osgi.container;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.util.List;
import java.util.Properties;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

public class BundleUtil {

	private static final Log log_ = LogFactory.getLog(BundleUtil.class);
    private static TransformerFactory transformerFac_ = null;
    private static DocumentBuilderFactory builderFac_ = null;
    
    public static final byte[] EMPTY_PLUGINS_BODY = "<plugins/>".getBytes();
    
    static {
        try {
            transformerFac_ = TransformerFactory.newInstance();
            builderFac_ = DocumentBuilderFactory.newInstance();
        } catch(Throwable th) {
            log_.error(th);
        }
    }
    
    public static byte[] readURL(URL url) {
        try {
            InputStream is = url.openStream();
            int count = 0, maxTry = 5;
            while(count == 0 && maxTry > 0) {
                count = is.available();
                maxTry --;
            }
            if(count != 0) {
                byte[] buff = new byte[count];
                int readCount = 0;  //byte number successfully readed
                while(readCount<count){
                    readCount += is.read(buff, readCount, count - readCount);
                }
                return buff;
            }
        } catch (Exception e) {
        	log_.error("", e);
        }
        return null;
    }
    
    public static Document parse(byte[] document) throws Exception {
        try {
            DocumentBuilder builder = builderFac_.newDocumentBuilder();
            ByteArrayInputStream bais = new ByteArrayInputStream(document);
            Document doc = builder.parse(bais);
            return doc;
        } catch (Exception e) {
            if(log_.isDebugEnabled())
                log_.debug("[parse] fail to parse " + document, e);
            throw e;
        }
    }

    public static byte[] unparse(Node node) {
        try {
            DOMSource source = new DOMSource(node);
            
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            OutputStreamWriter streamWriter = new OutputStreamWriter(out);
            StreamResult target = new StreamResult(streamWriter);    
            Transformer trans = transformerFac_.newTransformer();
            Properties pro = trans.getOutputProperties();
            //pro.setProperty(OutputKeys.ENCODING, "UTF-8");
            pro.setProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            trans.setOutputProperties(pro);
            trans.transform(source, target);
            
            out.flush();
            byte[] bytes = out.toByteArray();
            out.close();
            streamWriter.close();
            return bytes;
        } catch(Exception e) {
            if(log_.isDebugEnabled())
                log_.debug("[unparse]", e);
        }
        return null;
    }
    
    public static Document getEmptyPluginsResult() {
    		DocumentBuilder builder = null;
			try {
				builder = builderFac_.newDocumentBuilder();
			} catch (ParserConfigurationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    		Document doc = builder.newDocument();
    		doc.appendChild(doc.createElement("plugins"));
			return doc;
    }
    
    public static String join(List<String> list, String sep) {
    	StringBuffer buffer = new StringBuffer();
    	for(String key : list) {
    		buffer.append(key).append(sep);
    	}
    	String result = buffer.toString();
    	result = result.substring(0, result.length() - sep.length());
    	return result;
    }
    
    public static void fillBody(Document root, byte[] data) {
    	try {
			Document doc = parse(data);
			Element rootEle = root.getDocumentElement();
			rootEle.appendChild(root.importNode(doc.getDocumentElement(), true));
		} catch (Exception e) {
			log_.warn("[fillBody]", e);
		}
    	
    }
}
